//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.Generic;

namespace OpenLS.Spreadsheet
{
    internal struct RangeAddress
    {
        public static RangeAddress operator +(RangeAddress r, CellRelativeAddress b)
        {
            return new RangeAddress(r.TopLeft + b, r.BottomRight + b);
        }
        public bool Equals(RangeAddress a)
        {
            return TopLeft.Equals(a.TopLeft) &&
                BottomRight.Equals(a.BottomRight);
        }
        public override string ToString()
        {
            return this.topLeft.ToString() + ":" + bottomRight.ToString();
        }
       //\\ internal const int MaxValue = Dimension.MaxValue;//\\
        internal bool IsFullRow{get{return Right == Column.MaxIndex && Left == 0;}}
        internal bool IsFullColumn { get { return Bottom == Row.MaxIndex && Top == 0; } }
        public CellRelativeAddress Offset
        {
            get
            {
                return new CellRelativeAddress(bottomRight, topLeft);
            }
        }
        public IEnumerable<RangeAddress> GetRows()
        {
            for (int i = Top; i <= Bottom; i++)
            {
                yield return new RangeAddress(new CellAddress(i, Left), new CellAddress(i, Right));
            }
        }
        
        internal string Label
        {
            get
            {
                return TopLeft.Label + ":" + bottomRight.Label;
            }
        }
        internal RangeAddress(CellAddress cell1, CellAddress cell2)
        {
            int r1, r2;
            int c1, c2;
            if (cell1.Row < cell2.Row)
            {
                r1 = cell1.Row;
                r2 = cell2.Row;
            }
            else
            {
                r1 = cell2.Row;
                r2 = cell1.Row;
            }
            if (cell1.Column < cell2.Column)
            {
                c1 = cell1.Column;
                c2 = cell2.Column;
            }
            else
            {
                c1 = cell2.Column;
                c2 = cell1.Column;
            }
            topLeft = new CellAddress(r1, c1);
            bottomRight = new CellAddress(r2, c2);
        }
        
        private CellAddress topLeft;
        internal CellAddress TopLeft
        {
            get { return topLeft; }
        }
        internal int Top { get { return topLeft.Row; } }
        internal int Left { get { return topLeft.Column; } }
        internal int Right { get { return bottomRight.Column; } }
        internal int Bottom { get { return bottomRight.Row; } }
        private CellAddress bottomRight;
        internal CellAddress BottomRight
        {
            get { return bottomRight; }
        }
        public int RowSpan
        {
            get
            {
                return Bottom - Top + 1;
            }
        }
        public int ColumnSpan
        {
            get
            {
                return Right - Left + 1;
            }
        }
        internal CellAddress TopRight
        {
            get
            {
                return new CellAddress(Top, Right);
            }
        }
        internal CellAddress BottomLeft
        {
            get
            {
                return new CellAddress(Bottom, Left);
            }
        }
        public IEnumerable<CellAddress> GetCellAddresses ()
        {
            for (int row = Top; row <= Bottom; row++)
            {
                for (int column = Left; column <= Right; column++)
                    yield return new CellAddress(row, column);
            }
        }


        internal bool Intersects(RangeAddress rangeAddress)
        {
            if (Contains(rangeAddress.topLeft))
                return true;
            if (Contains(rangeAddress.TopRight))
                return true;
            if (Contains(rangeAddress.BottomLeft))
                return true;
            if (Contains(rangeAddress.bottomRight))
                return true;

            if (rangeAddress.Contains(topLeft))
                return true;
            if (rangeAddress.Contains(TopRight))
                return true;
            if (rangeAddress.Contains(BottomLeft))
                return true;
            if (rangeAddress.Contains(bottomRight))
                return true;
            if (this.Left <= rangeAddress.Left &&
                this.Right >= rangeAddress.Right &&
                rangeAddress.Top <= this.Top &&
                rangeAddress.Bottom >= this.Bottom
                )
                return true;
            if (rangeAddress.Left <= this.Left &&
                rangeAddress.Right >= this.Right &&
                this.Top <= rangeAddress.Top &&
                this.Bottom >= rangeAddress.Bottom
                )
                return true; return false;
        }
        internal bool Intersects(Column c)
        {
            return Left <= c.Index && Right >= c.Index;
        }

        internal bool Intersects(Row c)
        {
            return Top <= c.Index && Bottom >= c.Index;
        }
        internal bool Contains(CellAddress cellAddress)
        {
            return Between(Top, cellAddress.Row, Bottom) &&
                Between(Left, cellAddress.Column, Right);
        }
        internal bool Contains (RangeAddress rangeAddress)
        {
            return this.Top <= rangeAddress.Top &&
                   this.Left <= rangeAddress.Left &&
                   this.Right >= rangeAddress.Right &&
                   this.Bottom >= rangeAddress.Bottom;
        }
        static bool Between(int a, int b, int c)
        {
            return a <= b && b <= c;
        }

        internal RangeAddress Extend(CellAddress a)
        {
            CellAddress c1 = topLeft;
            CellAddress c2 = bottomRight;
            if (c1.Row > a.Row)
                c1 = new CellAddress(a.Row, c1.Column);
            if (c1.Column > a.Column)
                c1 = new CellAddress(c1.Row, a.Column);
            if (c2.Row < a.Row)
                c2 = new CellAddress(a.Row, c2.Column);
            if (c2.Column < a.Column)
                c2 = new CellAddress(c2.Row, a.Column);
            return new RangeAddress(c1, c2);
        }

        internal int Surface
        {
            get { return ColumnSpan*RowSpan; }
        }
    }

}
